package com.anmi.alfred.service.baseservice;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Elasticsearch 检索service，{@link RestHighLevelClient}提供了同步和异步两种实现，在这里先对客户端提供同步方法
 *
 * @author funnyx
 */
@Slf4j
public class SearchService {

  @Autowired private RestHighLevelClient restHighLevelClient;

  /**
   * 这个方法提供的参数和返回值，都交给客户端自行处理
   *
   * @param searchRequest
   * @return
   */
  protected SearchResponse search(SearchRequest searchRequest) {
    try {
      return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    } catch (IOException e) {
      log.error("search() has an error! {}", e.getMessage());
    }
    return null;
  }

  protected CountResponse count(CountRequest countRequest) {
    try {
      return restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
    } catch (IOException e) {
      log.error("count() has an error! {}", e.getMessage());
    }
    return null;
  }

  /**
   * 这里相当于 GET ip:port/_search
   *
   * @param index 索引名称
   * @return
   */
  protected List<String> matchAll(String index, int from, int size) {
    SearchRequest searchRequest = new SearchRequest(index);
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    sourceBuilder.query(
        QueryBuilders.matchAllQuery()); // Set the query. Can be any type of QueryBuilder
    // 这里取ES默认的
    sourceBuilder.from(from);
    sourceBuilder.size(size);
    sourceBuilder.timeout(new TimeValue(5, TimeUnit.SECONDS));
    searchRequest.source(sourceBuilder);
    SearchResponse response = search(searchRequest);
    return resolveSearchResponse(response);
  }

  /**
   * 现在分各个具体类来实现，该泛型方法没有意义，可以考虑删除！
   *
   * @return
   */
  protected <T> List<T> matchAll(String index, int from, int size, Class<T> clazz) {
    List<String> list = matchAll(index, from, size);
    return convert(list, clazz);
  }

  protected List<String> resolveSearchResponse(SearchResponse searchResponse) {
    List<String> sourceLists = Lists.newArrayList();
    if (searchResponse != null && RestStatus.OK.equals(searchResponse.status())) {
      SearchHits searchHits = searchResponse.getHits();
      SearchHit[] hits = searchHits.getHits();
      for (SearchHit hit : hits) {
        sourceLists.add(hit.getSourceAsString());
      }
    }
    return sourceLists;
  }

  protected long resolveSearchHItsTotalNum(SearchResponse searchResponse) {
    long totalNum = 0L;
    if (searchResponse != null && RestStatus.OK.equals(searchResponse.status())) {
      SearchHits hits = searchResponse.getHits();
      totalNum = hits.getTotalHits().value;
    }
    return totalNum;
  }

  protected <T> List<T> convert(List<String> source, Class<T> clazz) {
    List<T> result = Lists.newArrayList();
    if (source == null || source.size() == 0) {
      return result;
    }
    source.forEach(temp -> result.add(JSON.parseObject(temp, clazz)));
    return result;
  }
}
